package com.gaga.console.core.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import com.gaga.common.enums.*;
import com.gaga.common.utils.AudioPlayerUtils2;
import com.gaga.common.utils.DeviceInfoUtils;
import com.gaga.console.base.entity.sse.PushMessageDto;
import com.gaga.console.base.utils.MyDecimalUtil;
import com.gaga.console.base.utils.SseEmitterServerUtils;
import com.gaga.console.core.entity.dto.*;
import com.gaga.console.core.service.AudioPlayQueueService;
import com.gaga.console.core.service.BvAudioPlayService;
import com.gaga.console.core.service.BvConfigService;
import com.gaga.console.core.service.MainVideoService;
import com.gaga.metadata.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
@Slf4j
public class AudioPlayQueueServiceImpl implements AudioPlayQueueService {
    private final ConcurrentLinkedDeque<AudioPlayDto> anchorQueue = new ConcurrentLinkedDeque<>();
    //    private final ConcurrentLinkedDeque<AudioDto> assistantQueue = new ConcurrentLinkedDeque<>();
    private final ExecutorService anchorExecutor = ThreadUtil.newSingleExecutor();
//    private final ExecutorService assistantExecutor = Executors.newSingleThreadExecutor();

    private final AudioPlayerUtils2 anchorAudioPlayer = new AudioPlayerUtils2();
//    private final AudioPlayerUtils2 assistantAudioPlayer = new AudioPlayerUtils2();

    private final AtomicBoolean isAnchorPlaying = new AtomicBoolean(false);

    private volatile boolean startLive = true;

    private volatile AtomicBoolean isMuting = new AtomicBoolean(false);
//    private volatile boolean isAssistantPlaying = false;

    @Autowired
    private BvConfigService bvConfigService;

    @Autowired
    private MainVideoService mainVideoService;

    @Autowired
    private BvAudioPlayService bvAudioPlayService;

    /**
     * 将文件插入到第一条
     *
     * @param audioDto 文件名
     * @param type     播放器类型（决定文件加入哪个队列）
     *                 如果类型为 ANCHOR，则加入锚点队列并尝试播放；
     *                 如果类型为 ASSISTANT，则加入助手队列并尝试播放。
     * @throws IllegalArgumentException 如果文件名或播放器类型为空。
     */
    @Override
    public void insertFirstToQueue(AudioPlayDto audioDto, PlayerType type) {
        if (startLive) {
            return;
        }
        // 将文件加入锚点队列
        anchorQueue.addFirst(audioDto);
        // 尝试开始锚点播放
        tryStartAnchorPlayback();
    }

    @Override
    public void addToQueue(AudioPlayDto audioDto, PlayerType type) {
        // 将文件加入锚点队列
        anchorQueue.addLast(audioDto);
        if (startLive) {
            if (anchorQueue.size() >= 4) {
                startLive = false;
                // 尝试开始锚点播放
                bvAudioPlayService.updateStartLiveStep(StartLiveStepType.playing);
                bvAudioPlayService.setLiveStatus(LiveRoomStatusType.playing);
                tryStartAnchorPlayback();
            }
        } else {
            tryStartAnchorPlayback();
        }
    }

    @Override
    public void stopLive() {
        log.info("停止直播，清理所有资源");

        // 清理队列
        int queueSize = anchorQueue.size();
        anchorQueue.clear();
        log.info("清理了{}个待播放音频", queueSize);

        // 停止当前播放
        try {
            anchorAudioPlayer.stop();
            log.info("停止当前播放的音频");
        } catch (Exception e) {
            log.error("停止音频播放器失败: " + e.getMessage(), e);
        }

        // 重置状态
        isAnchorPlaying.set(false);
        startLive = true;

        log.info("直播停止完成，所有资源已释放");
    }

    @Override
    public Integer getQueueSize(PlayerType playerType) {
        return anchorQueue.size();
    }

    @Override
    public Integer getQueueSizeByScriptType(ScriptType scriptType) {
        return (int) anchorQueue.stream()
                .filter(dto -> dto.getScriptType() == scriptType)
                .count();
    }

    @Override
    public void realTimeChangeSpeed(RealTimeChangeSpeedDto dto) {
        if (StringUtils.isBlank(dto.getPlayerType()) || PlayerType.getPlayerTypeByCode(dto.getPlayerType()) == null) {
            anchorAudioPlayer.setSpeed(dto.getSpeed().floatValue());
            return;
        }
        if (PlayerType.getPlayerTypeByCode(dto.getPlayerType()).equals(anchorAudioPlayer.getPlayerType())) {
            anchorAudioPlayer.setSpeed(dto.getSpeed().floatValue());
        }
    }

    @Override
    public void realTimeChangeVolumn(RealTimeChangeVolumnDto dto) {
        if (StringUtils.isBlank(dto.getPlayerType()) || PlayerType.getPlayerTypeByCode(dto.getPlayerType()) == null) {
            anchorAudioPlayer.setVolume(dto.getVolumn().floatValue());
            return;
        }
        if (PlayerType.getPlayerTypeByCode(dto.getPlayerType()).equals(anchorAudioPlayer.getPlayerType())) {
            anchorAudioPlayer.setVolume(dto.getVolumn().floatValue());
        }
    }

    @Override
    public void realTimeChangeGainDb(RealTimeChangeGainDbDto dto) {
        anchorAudioPlayer.setBandGain(dto.getBandIndex(), dto.getGainDb().floatValue());
    }

    @Override
    public void pause() {
        anchorAudioPlayer.pause();
    }

    @Override
    public void play() {
        //继续直播
        anchorAudioPlayer.play();
    }

    @Override
    public void startMute() {
        RealTimeChangeVolumnDto realTimeChangeVolumnDto = new RealTimeChangeVolumnDto().setVolumn(0.1);
        realTimeChangeVolumn(realTimeChangeVolumnDto);
        isMuting.set(true);
    }

    @Override
    public void endMute() {
        isMuting.set(false);
        ConfigDto configDto = bvConfigService.getConfig();
        RealTimeChangeVolumnDto realTimeChangeVolumnDto = new RealTimeChangeVolumnDto();
        realTimeChangeVolumnDto.setPlayerType(anchorAudioPlayer.getPlayerType().getCode());

        if (PlayerType.ANCHOR.equals(anchorAudioPlayer.getPlayerType())) {
            realTimeChangeVolumnDto.setVolumn(new BigDecimal(configDto.getAudioSetting().getVolume().getAnchor()).divide(new BigDecimal(100)).doubleValue());
            realTimeChangeVolumn(realTimeChangeVolumnDto);
        } else if (PlayerType.ASSISTANT.equals(anchorAudioPlayer.getPlayerType())) {
            realTimeChangeVolumnDto.setVolumn(new BigDecimal(configDto.getAudioSetting().getVolume().getAssistant()).divide(new BigDecimal(100)).doubleValue());
            realTimeChangeVolumn(realTimeChangeVolumnDto);
        }

    }

    /**
     * 尝试启动锚点播放
     * 此方法用于检查当前是否可以启动锚点播放如果当前没有锚点正在播放且锚点队列不为空，则开始播放
     * 此方法是同步的，以确保并发情况下锚点播放状态的一致性
     */
    private synchronized void tryStartAnchorPlayback() {

        // 检查当前是否有锚点正在播放以及锚点队列是否为空
        log.error("==4=play isAnchorPlaying:{}, anchorQueueSize {}", isAnchorPlaying.get(), anchorQueue.size());
        if (!isAnchorPlaying.get() && !anchorQueue.isEmpty()) {
            // 设置锚点播放状态为正在播放
            isAnchorPlaying.set(true);
            // 提交任务以处理锚点队列
            anchorExecutor.submit(this::processAnchorQueue);
        }
    }

    /**
     * 尝试启动助手播放功能
     * 此方法用于检查当前是否可以启动助手播放，并在条件满足时开始播放
     * 它首先检查当前是否有助手播放正在进行（通过isAssistantPlaying判断），以及助手队列是否为空（通过assistantQueue.isEmpty()判断）
     * 如果当前没有助手播放正在进行且队列不为空，则将isAssistantPlaying设置为true，并提交任务到助手执行器（assistantExecutor）以处理助手队列
     * <p>
     * 注：此方法是同步的（synchronized），以确保并发情况下对助手播放状态和队列的访问是线程安全的
     */
//    private synchronized void tryStartAssistantPlayback() {
//        // 检查当前是否有助手播放正在进行，以及助手队列是否为空
//        if (!isAssistantPlaying && !assistantQueue.isEmpty()) {
//            // 设置助手播放状态为正在进行
//            isAssistantPlaying = true;
//            // 提交处理助手队列的任务到助手执行器
//            assistantExecutor.submit(this::processAssistantQueue);
//        }
//    }

    /**
     * 处理锚点队列
     * 本方法调用通用的processQueue方法来处理锚点类型的播放队列
     * 它专门处理与锚点相关的音频播放逻辑
     */
    private void processAnchorQueue() {
        // 调用处理队列的方法，指定播放器类型为锚点，传递锚点队列和锚点音频播放器作为参数
        processQueue(PlayerType.ANCHOR, anchorQueue, anchorAudioPlayer);
    }

    /**
     * 处理助理队列中的音频播放请求
     * 此方法通过调用更通用的processQueue方法来处理助理的音频播放队列
     * 它专门用于处理类型为ASSISTANT的玩家的音频队列
     */
//    private void processAssistantQueue() {
//        // 调用通用的processQueue方法，传入助理特定的队列和音频播放器实例
//        processQueue(PlayerType.ASSISTANT, assistantQueue, assistantAudioPlayer);
//    }

    /**
     * 处理播放队列中的音频文件
     *
     * @param type   播放器类型，用于区分不同类型的音频播放
     * @param queue  音频文件队列，存储待播放的音频文件名
     * @param player 音频播放实用工具类实例，用于实际的音频播放操作
     */
    private void processQueue(PlayerType type, ConcurrentLinkedDeque<AudioPlayDto> queue, AudioPlayerUtils2 player) {
        // 从队列中获取下一个音频文件
        AudioPlayDto audioDto = queue.poll();
        if (audioDto == null) {
            isAnchorPlaying.set(false);
            return;
        }

        //时间超过一分钟的报时任务直接抛弃
        if (audioDto.getBroadTime() != null &&
                audioDto.getBroadTime() &&
                audioDto.getFutureTime() != null &&
                !isWithinOneMinute(audioDto.getFutureTime())) {
            log.error("时间超过一分钟的报时任务直接抛弃: {},当前时间：{},播报时间：{}", audioDto.getText(), new Date(), audioDto.getFutureTime());
            isAnchorPlaying.set(false);
            tryStartAnchorPlayback();
            return;
        }

        String file = audioDto.getAudioFilePath();
        // 如果队列中还有文件，则尝试播放
        File awvFile = new File(file);

        if (file != null && awvFile.exists()) {
            // 检查音频文件大小，确保不是空文件
            if (awvFile.length() < 100) { // 如果文件小于100字节，可能是损坏文件
                log.error("音频文件可能损坏或为空: {}，跳过播放", file);
                // 自动触发下一个播放
                isAnchorPlaying.set(false);
                tryStartAnchorPlayback();
                return;
            }

            // 添加一个小的随机延迟，确保时间戳不会完全相同
            try {
                Thread.sleep(50);  // 添加50毫秒的基础延迟
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("延迟被中断: " + e.getMessage());
            }

            if (audioDto.getIntervalMin() != null && audioDto.getIntervalMax() != null) {
                int randomSleepTime = ThreadLocalRandom.current().nextInt(audioDto.getIntervalMin(), audioDto.getIntervalMax() + 1);
                try {
                    Thread.sleep(randomSleepTime);
                } catch (InterruptedException e) {
                    // 处理线程中断（例如取消任务）
                    Thread.currentThread().interrupt(); // 恢复中断状态
                    log.error("休眠被中断: " + e.getMessage());
                }
            }
            ConfigDto configDto = bvConfigService.getConfig();

            // 尝试播放音频文件
            playAudio(audioDto, type, player, queue, configDto);
        }
    }

    private static void pushMessage(AudioPlayDto audioDto, ConcurrentLinkedDeque<AudioPlayDto> anchorQueue) {
        if (StringUtils.isBlank(audioDto.getChannelId()) || StringUtils.isBlank(audioDto.getText())) {
            return;
        }

        PushMessageDto pushMessageDto = new PushMessageDto();
        pushMessageDto.setMessage(audioDto.getText());

        switch (audioDto.getScriptType()) {
            case INSERT_AUDIO:
                pushMessageDto.setType(PushMessageType.insertAudioWaitPlay);
                break;
            case KEYWORD:
                pushMessageDto.setType(PushMessageType.keywordWaitPlay);
                break;
            case USER_ENTER:
                pushMessageDto.setType(PushMessageType.userEnterWaitPlay);
                break;
            case RANDOM_AUDIO:
                pushMessageDto.setType(PushMessageType.randomAudioWaitPlay);
                break;
            case MAIN_AUDIO:
                pushMessageDto.setType(PushMessageType.mainAudioPlayFile);
                pushMessageDto.setPlayScriptId(audioDto.getPlayScriptId());
                break;
            default:
                break;
        }

        if (pushMessageDto.getType() != null) {
            //推送待播放消息
            try {
                SseEmitterServerUtils.sendMessage(audioDto.getChannelId(), pushMessageDto);
            } catch (Exception e) {
                log.error("推送待播放消息失败: " + e.getMessage());
            }
        }
    }

    private static void clearGenMessage(AudioPlayDto audioDto, ConcurrentLinkedDeque<AudioPlayDto> anchorQueue) {

        //推送待播放后将待生成的消息清空
        PushMessageDto pushNullMessageDto = new PushMessageDto();

        Optional<AudioPlayDto> thirdOpt = anchorQueue.stream()
                .filter(item -> item.getScriptType().equals(audioDto.getScriptType()))
                .skip(2)
                .findFirst();

        PushMessageDto pushMessageDto = new PushMessageDto();
        if (thirdOpt.isPresent()) {
            pushMessageDto.setMessage("");
        }

        switch (audioDto.getScriptType()) {
            case INSERT_AUDIO:
                pushNullMessageDto.setType(PushMessageType.insertAudioWaitGen);
                break;
            case KEYWORD:
                pushNullMessageDto.setType(PushMessageType.keywordWaitGen);
                break;
            case USER_ENTER:
                pushNullMessageDto.setType(PushMessageType.userEnterWaitGen);
                break;
            case RANDOM_AUDIO:
                pushNullMessageDto.setType(PushMessageType.randomAudioWaitGen);
                break;
            default:
                break;
        }

        if (pushNullMessageDto.getType() != null) {
            //将待生成区域置空
            SseEmitterServerUtils.sendMessage(audioDto.getChannelId(), pushNullMessageDto);
        }
    }

    private static void clearPlayMessage(AudioPlayDto audioDto) {

        //推送待播放后将待生成的消息清空
        PushMessageDto pushNullMessageDto = new PushMessageDto();
        pushNullMessageDto.setMessage("");

        switch (audioDto.getScriptType()) {
            case INSERT_AUDIO:
                pushNullMessageDto.setType(PushMessageType.insertAudioWaitPlay);
                break;
            case KEYWORD:
                pushNullMessageDto.setType(PushMessageType.keywordWaitPlay);
                break;
            case USER_ENTER:
                pushNullMessageDto.setType(PushMessageType.userEnterWaitPlay);
                break;
            case RANDOM_AUDIO:
                pushNullMessageDto.setType(PushMessageType.randomAudioWaitPlay);
                break;
            default:
                break;
        }

        if (pushNullMessageDto.getType() != null) {
            //将待生成区域置空
            SseEmitterServerUtils.sendMessage(audioDto.getChannelId(), pushNullMessageDto);
        }
    }

    /**
     * 播放音频文件
     *
     * @param audioDto 音频文件的路径
     * @param type     播放器类型，决定播放完毕后的行为
     * @param player   音频播放器实例，用于控制音频播放
     */
    private void playAudio(AudioPlayDto audioDto, PlayerType type, AudioPlayerUtils2 player, ConcurrentLinkedDeque<AudioPlayDto> queue, ConfigDto configDto) {
        try {
            //todo 需要控制死循环
            while (LiveRoomStatusType.pause.getCode().equals(bvAudioPlayService.getLiveRoomStatus())) {
                ThreadUtil.sleep(2000);
            }

            log.error("准备开始播放音频 [{}]: {}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")), audioDto.getAudioFilePath());
            // 初始化播放器，设置音频文件路径和设备
            player.init(audioDto.getAudioFilePath(), bvConfigService.getSelectDeviceName(), audioDto.getPlayerType());
            // 设置播放完成后的回调
            player.setOnPlaybackFinished(() -> {
                log.error("播放音频完成: " + audioDto.getAudioFilePath());
                log.error("触发播放完成回调，重置 isAnchorPlaying=false");

                try {
                    // 确保播放器资源被释放
                    player.stop();

                    // 清理待播放消息
                    clearPlayMessage(audioDto);

                } finally {
                    // 无论如何都要重置状态并尝试播放下一个
                    isAnchorPlaying.set(false);
                    tryStartAnchorPlayback();
                }
            });

            //推送等待播放消息
            pushMessage(audioDto, queue);
            //将待生成文件清理
            clearGenMessage(audioDto, queue);

            sendMainLog(type, audioDto);

            mainVideoService.matchMainVideo(audioDto);

            float speed = MyDecimalUtil.getFloatSpeed(configDto.getAudioSetting().getPlay().getAnchor());
            float volume = MyDecimalUtil.getFloatVolume(configDto.getAudioSetting().getVolume().getAnchor());
            if (PlayerType.ASSISTANT.equals(type)) {
                speed = MyDecimalUtil.getFloatSpeed(configDto.getAudioSetting().getPlay().getAssistant());
                volume = MyDecimalUtil.getFloatVolume(configDto.getAudioSetting().getVolume().getAssistant());
            }
            ConfigDto.Equalizer equalizer = configDto.getAudioSetting().getEqualizer();

            player.setSpeed(speed);
            if (!isMuting.get()) {
                player.setVolume(volume);
            } else {
                player.setVolume(0.1f);
            }
            //音频音效设置
            player.setBandGain(3, equalizer.getList().get(0) - AudioPlayerUtils2.FREQUENCIES[3]);

            //            if (equalizer != null && CollectionUtils.isNotEmpty(equalizer.getList())) {
//                for (int i = 0; i < equalizer.getList().size(); i++) {
//                    player.setBandGain(i, equalizer.getList().get(i) - AudioPlayerUtils2.FREQUENCIES[i]);
//                }
//            }
            log.error("开始播放音频: " + audioDto.getAudioFilePath());
            player.play();

            // 添加一个短暂等待，确保播放真正开始
            try {
                Thread.sleep(100);  // 等待100毫秒，确保播放引擎启动
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            log.info("播放已启动: " + audioDto.getAudioFilePath());
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
            log.error("播放失败" + e.getMessage());

            // 推送错误信息到前端
            PushMessageDto pushMessageDto = new PushMessageDto();
            pushMessageDto.setType(PushMessageType.liveError);
            pushMessageDto.setMessage("音频播放失败：" + e.getMessage());
            if (audioDto != null && audioDto.getChannelId() != null) {
                SseEmitterServerUtils.sendMessage(audioDto.getChannelId(), pushMessageDto);
            }

            try {
                // 确保播放器资源被释放
                player.stop();
            } catch (Exception ex) {
                log.error("停止播放器失败: " + ex.getMessage());
            } finally {
                // 重置播放状态，确保可以继续播放下一个音频
                isAnchorPlaying.set(false);
                tryStartAnchorPlayback();
            }
        }
    }


    private void sendMainLog(PlayerType type, AudioPlayDto audioDto) {
        // 开始播放音频
        PushMessageDto pushMessageDto = new PushMessageDto();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("【").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))).append("】");
        stringBuilder.append("【").append(audioDto.getScriptType().getInfo()).append("】");
        if (StringUtils.isNotBlank(audioDto.getPlayFileName())) {
            stringBuilder.append("【").append(audioDto.getPlayFileName()).append("】");
        }
        stringBuilder.append("【").append(type.getDisplayName()).append("】");
        if (audioDto.getIsSmartReply()) {
            stringBuilder.append("【原文本：").append(audioDto.getOldText()).append("】");
            stringBuilder.append("【泛化后：").append(audioDto.getText()).append("】");
        } else {
            stringBuilder.append("【文本：").append(audioDto.getText()).append("】");
        }

        pushMessageDto.setMessage(stringBuilder.toString());
        pushMessageDto.setType(PushMessageType.playLog);
        pushMessageDto.setAudioDuration(DeviceInfoUtils.getAudioDuration(audioDto.getAudioFilePath()));
        SseEmitterServerUtils.sendMessage(audioDto.getChannelId(), pushMessageDto);

        if (StringUtils.isNotBlank(audioDto.getPlayLogPath())) {
            stringBuilder.append("【音频文件路径：").append(audioDto.getAudioFilePath()).append("】");
            // 追加写入文件
            try (BufferedWriter writer = new BufferedWriter(
                    new FileWriter(audioDto.getPlayLogPath(), true))) { // true 表示追加模式
                writer.write(stringBuilder.toString());
                writer.newLine(); // 添加换行符
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static boolean isWithinOneMinute(LocalDateTime targetDateTime, ZoneId zone) {
        Instant targetInstant = targetDateTime.atZone(zone).toInstant();
        Instant nowInstant = Instant.now();
        return Math.abs(Duration.between(nowInstant, targetInstant).toMillis()) <= 300_000;
    }

    // 使用系统默认时区
    public static boolean isWithinOneMinute(LocalDateTime targetDateTime) {
        return isWithinOneMinute(targetDateTime, ZoneId.systemDefault());
    }

    public static void main(String[] args) {
        System.out.println(new BigDecimal(133).divide(new BigDecimal(100)).doubleValue());
        new BigDecimal(133).divide(new BigDecimal(100)).doubleValue();
    }

}
